[iOS 8] Swiftでデザインパターン No.8 Abstract Factory
Abstract Factory
Abstract Factory とは
日本語では「抽象的な工場」と訳されることが多いらしいです。
Abstract Factory は互いに関連したり依存し合うオブジェクト群を、その具象クラスを明確にせずに生成するためのインタフェースを提供するパターンです。
クラス図
ポイント
- ファクトリークラスごとに、生成するプロダクトが決まっている
- Product1 を生成するのは ConcreteFactory1
- Product2 を生成するのは ConcreteFactory2
サンプルコード
Emacs と Vim で、コピー&ペーストを実行するプログラムです。
CommandFactory(AbstractFactory)
enum Editor { case Emacs case Vim func name() -> String { switch self { case Emacs: return "Emacs" case Vim: return "Vim" } } } class CommandFactory { class func getFactory(editor: Editor) -> CommandFactory { switch editor { case .Emacs: return EmacsCommandFactory() case .Vim: return VimCommandFactory() } } func createCopy() -> Copy { fatalError("must be overridden") } func createPaste() -> Paste { fatalError("must be overridden") } }
AbstractFactory クラスです。
コマンドを生成する工場を表現する抽象クラスです。 「コピー」と「ペースト」のコマンド(プロダクト)を生成するメソッドを持ちます。 また、適切なファクトリークラスを返すgetFactoryというクラスメソッドも持ちます。このメソッドの引数は enum です。
EmacsCommandFactory(ConcreteFactory1)
class EmacsCommandFactory: CommandFactory { override func createCopy() -> Copy { return EmacsCopy() } override func createPaste() -> Paste { return EmacsPaste() } }
ConcreteFactory1 クラスです。
createCopy(),createPaste()では、それぞれ Emacs 用のコマンドを返します。
VimCommandFactory(ConcreteFactory2)
class VimCommandFactory: CommandFactory { override func createCopy() -> Copy { return VimCopy() } override func createPaste() -> Paste { return VimPaste() } }
ConcreteFactory2 クラスです。
createCopy(),createPaste()では、それぞれ Vim 用のコマンドを返します。
Copy(AbstractProductA)
class Copy { func execute() {} }
AbstractProductA クラスです。
Copy コマンドを表現する抽象クラスです。 実行メソッドexecute()を持ちます。
EmacsCopy(ProductA1)
class EmacsCopy: Copy { override func execute() { println("M-w") } }
ProductA1 クラスです。
Emacs の Copy を表現します。
VimCopy(ProductA2)
class VimCopy: Copy { override func execute() { println("y") } }
ProductA2 クラスです。
Vim の Copy を表現します。
Paste(AbstractProductB)
class Paste { func execute() {} }
AbstractProductB クラスです。
Paste コマンドを表現する抽象クラスです。 実行メソッドexecute()を持ちます。
EmacsPaste(ProductB1)
class EmacsPaste: Paste { override func execute() { println("C-y") } }
ProductB1 クラスです。
Emacs の Paste を表現します。
VimPaste(ProductB2)
class VimPaste: Paste { override func execute() { println("p") } }
ProductB2 クラスです。
Vim の Paste を表現します。
実行
func main() { copyAndPaste(.Emacs) // Emacs でコピー&ペースト copyAndPaste(.Vim) // Vim でコピー&ペースト }
func copyAndPaste(editor: Editor) { let commandFactory = CommandFactory.getFactory(editor) println("### " + editor.name() + " ###") print("Copy:t") commandFactory.createCopy().execute() print("Paste:t") commandFactory.createPaste().execute() }
実行結果
### Emacs ### Copy: M-w Paste: C-y ### Vim ### Copy: y Paste: p
Emacs と Vim のコピー&ペーストでした。
まとめ
- Swift の enum はメソッドを定義することができる
- 変数/定数が enum 型であると推論されている場合は、型名を省略し .<メンバ名> と記述することができる